import { NextFunction, Request, Response } from "express";
import {
  UserService,
  PostService,
  BoardService,
  CommentService,
} from "../services";
import { PostSchema } from "../schemas";
import { paginate } from "../utils";
import { Like } from "typeorm";
import { RoleUser } from "../entities/user";

export class PostController {
  public static async create(
    req: Request<unknown, unknown, PostSchema>,
    res: Response,
    next: NextFunction,
  ) {
    try {
      const user = await UserService.findById(res.locals.user.id);
      const board = await BoardService.findById(req.body.boardId);
      if (!user || !board) {
        return res.status(400).json({
          status: "fail",
          message: "Invalid parameters",
        });
      }
      const post = await PostService.create({ ...req.body, user, board });
      res.status(201).json(post);
    } catch (err) {
      next(err);
    }
  }

  public static async findOne(req: Request, res: Response, next: NextFunction) {
    try {
      const post = await PostService.findById(req.params.id);
      if (!post) {
        return res.status(404).json({
          status: "fail",
          message: "Post not found",
        });
      }
      res.json(post);
    } catch (err) {
      next(err);
    }
  }

  public static async findMany(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    try {
      const posts = await PostService.find({
        ...paginate(req),
        where: [
          { title: Like(`%${req.query.q || ""}%`) },
          { content: Like(`%${req.query.q || ""}%`) },
        ],
      });
      res.json({
        data: posts[0],
        total: posts[1],
      });
    } catch (err) {
      next(err);
    }
  }

  public static async findComments(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    try {
      const post = await PostService.findById(req.params.id);
      if (!post) {
        return res.status(404).json({
          status: "fail",
          message: "Post not found",
        });
      }
      const comments = await CommentService.find({
        ...paginate(req),
        where: {
          content: Like(`%${req.query.q || ""}%`),
          post: {
            id: post.id,
          },
        },
      });
      res.json({ data: comments[0], total: comments[1] });
    } catch (err) {
      next(err);
    }
  }

  public static async update(req: Request, res: Response, next: NextFunction) {
    try {
      const post = await PostService.findById(req.params.id);
      if (!post) {
        return res.status(404).json({
          status: "fail",
          message: "Post not found",
        });
      }
      if (
        res.locals.user.id !== post.user.id &&
        res.locals.user.role !== RoleUser.ADMIN
      ) {
        return res.status(403).json({
          status: "fail",
          message: "Not allowed",
        });
      }
      await PostService.update(post.id, req.body);
      res.sendStatus(200);
    } catch (err) {
      next(err);
    }
  }

  public static async remove(req: Request, res: Response, next: NextFunction) {
    try {
      const post = await PostService.findById(req.params.id);
      if (!post) {
        return res.status(404).json({
          status: "fail",
          message: "Post not found",
        });
      }
      if (
        res.locals.user.id !== post.user.id &&
        res.locals.user.role !== RoleUser.ADMIN
      ) {
        return res.status(403).json({
          status: "fail",
          message: "Not allowed",
        });
      }
      await PostService.remove(post);
      res.sendStatus(200);
    } catch (err) {
      next(err);
    }
  }
}
